package com.winit.deploy.server;

import com.winit.common.util.ObjectToString;
import com.winit.core.server.TomcatServer;
import com.winit.core.server.base.CmdOutputHandler;
import com.winit.deploy.bean.DubboVerifyInfo;
import com.winit.deploy.bean.WinitTomcatInfo;
import com.winit.project.util.ProjectUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.util.List;

/**
 * Created by wangjian on 16/8/11.
 */
public class WinitTomcatServer extends TomcatServer {

    static final Logger logger = LoggerFactory.getLogger(WinitTomcatServer.class);

    private WinitTomcatInfo winitTomcatInfo;
    //dubbo校验参数
    private List<DubboVerifyInfo> dubboList = null;

    public WinitTomcatServer(String ip, String userName, Integer port, WinitTomcatInfo winitTomcatInfo, List<DubboVerifyInfo> dubboList) throws Exception {
        super(ip, userName, port,winitTomcatInfo.getServerPath());
        this.winitTomcatInfo = winitTomcatInfo;
        this.dubboList = dubboList;
    }

    public WinitTomcatServer(String ip, String userName, Integer port, WinitTomcatInfo winitTomcatInfo) throws Exception {
        super(ip, userName, port,winitTomcatInfo.getServerPath());
        this.winitTomcatInfo = winitTomcatInfo;
    }

    public void setDubboList(List<DubboVerifyInfo> dubboList){
        this.dubboList = dubboList;
    }

    public WinitTomcatInfo getWinitTomcatInfo(){
        return this.winitTomcatInfo;
    }

    /**
     * 推送结束后,校验临时目录下war包是否存在
     * @throws Exception
     */
    public void doCheckWar() throws Exception{
        if(StringUtils.isEmpty(this.winitTomcatInfo.getWarTempDir())
                || StringUtils.isEmpty(this.winitTomcatInfo.getWarName())){
            logger.error("WinitTomcatServer:校验是否推送成功,参数存在空值."+ ObjectToString.getString(this.winitTomcatInfo));
            throw new Exception("校验是否推送成功,参数存在空值");
        }

        StringBuffer cmd = new StringBuffer();
        cmd.append("ls ").append(this.winitTomcatInfo.getWarTempDir()).append(" | grep ^").append(this.winitTomcatInfo.getWarName())
                .append(".war$");
        this.initHandler();
        this.doExec(this.handler,cmd.toString());
        logger.info("WinitTomcatServer:校验是否推送成功,返回:"+this.handler.getMessage());
        if(!this.handler.isSuccess()){
            logger.error("WinitTomcatServer:校验是否推送成功失败.返回:"+this.handler.getMessage());
            throw new Exception("校验是否推送成功失败."+this.handler.getMessage());
        }
        if(StringUtils.isEmpty(this.handler.getMessage())){
            logger.error("WinitTomcatServer:校验是否推送成功,终端机推送包不存在.");
            throw new Exception("校验是否推送成功,终端机推送包不存在.");
        }
    }

    /**
     * 备份应用
     * 1.进入工程存放目录
     * 2.判断工程文件夹是否存在  存在继续  不存在退出
     * 3.将原工程打包至备份目录
     */
    public void doBakUp() throws Exception{
        String projectDir =  this.winitTomcatInfo.getProjectDir();
        String warName =  this.winitTomcatInfo.getWarName();
        String backUpPath=  this.winitTomcatInfo.getBackUpPath();
        String backUpDir=  this.winitTomcatInfo.getBackUpDir();

        if(StringUtils.isEmpty(projectDir)
                || StringUtils.isEmpty(warName)
                || StringUtils.isEmpty(backUpPath)){
            logger.error("WinitTomcatServer:备份应用,参数存在空值."+ ObjectToString.getString(this.winitTomcatInfo));
            throw new Exception("备份应用,参数存在空值");
        }

        StringBuffer cmd = new StringBuffer();
        cmd.append("ls ").append(projectDir).append(" | grep ^").append(warName).append("$ && cd ").append(projectDir)
                .append(" && tar -zcf ").append(backUpPath).append(" ").append(warName);
        this.doExec(cmd.toString());
        //删除旧备份文件
        if(!StringUtils.isEmpty(backUpDir) && !StringUtils.isEmpty(warName)){
            cmd = new StringBuffer();
            cmd.append("source /etc/profile && ls ").append(projectDir).append(" | grep ^").append(warName).append("- && cd ")
                    .append(backUpDir).append(" && rm -rf `ls -t ").append(warName).append("-* | tail -n+4`");
            this.doExec(cmd.toString());
        }
    }

    /**
     * 拷贝工程
     * 1.进入工程存放目录
     * 2.判断工程文件夹是否存在  存在继续  不存在先创建再继续
     * 3.将war包拷贝至工程文件夹目录下并解压
     * 4.解压后删除war包
     */
    public boolean doInstall() throws Exception{
        if(StringUtils.isEmpty(this.winitTomcatInfo.getProjectDir())
                || StringUtils.isEmpty(this.winitTomcatInfo.getWarName())
                || StringUtils.isEmpty(this.winitTomcatInfo.getWarTempDir())){
            logger.error("WinitTomcatServer:安装程序,参数存在空值."+ ObjectToString.getString(this.winitTomcatInfo));
            throw new Exception("安装程序,参数存在空值");
        }
        this.initHandler();
        this.doExec(this.handler,"ls "+this.winitTomcatInfo.getProjectDir()+" | grep ^"+this.winitTomcatInfo.getWarName()+"$");

        if(!this.handler.isSuccess()){
            logger.error("WinitTomcatServer:安装程序,查询工程目录是否存在失败.返回:"+this.handler.getMessage());
            throw new Exception("安装程序,查询工程目录是否存在失败."+this.handler.getMessage());
        }
        //目录不存在 先创建
        if(StringUtils.isEmpty(this.handler.getMessage())){
            this.initHandler();
            this.doExec(this.handler,"cd "+this.winitTomcatInfo.getProjectDir()+" && mkdir "+this.winitTomcatInfo.getWarName());
            if(!this.handler.isSuccess()){
                logger.error("WinitTomcatServer:安装程序,创建工程目录失败.返回:"+this.handler.getMessage());
                throw new Exception("安装程序,创建工程目录失败."+this.handler.getMessage());
            }
        }

        StringBuffer cmd = new StringBuffer();
        cmd.append("rm -rf ").append(this.winitTomcatInfo.getProjectDir()).append("/").append(this.winitTomcatInfo.getWarName()).append("/* &&")
                .append("cp ").append(this.winitTomcatInfo.getWarTempDir()).append("/").append(this.winitTomcatInfo.getWarName()).append(".war ").append(this.winitTomcatInfo.getProjectDir()).append("/")
                .append(this.winitTomcatInfo.getWarName()).append("/").append(this.winitTomcatInfo.getWarName()).append(".war && ")
                .append("rm -rf ").append(this.winitTomcatInfo.getWarTempDir()).append("/").append(this.winitTomcatInfo.getWarName()).append(".war && ")
                .append(" cd ").append(this.winitTomcatInfo.getProjectDir()).append("/").append(this.winitTomcatInfo.getWarName()).append(" && ")
                .append(" unzip -q -o ").append(this.winitTomcatInfo.getWarName()).append(".war && ")
                .append("rm -rf ").append(this.winitTomcatInfo.getProjectDir()).append("/").append(this.winitTomcatInfo.getWarName()).append("/")
                .append(this.winitTomcatInfo.getWarName()).append(".war");
        this.initHandler();
        this.doExec(this.handler,cmd.toString());

        if(!this.handler.isSuccess()){
            logger.error("WinitTomcatServer:安装程序失败.返回:"+this.handler.getMessage());
            throw new Exception("安装程序失败."+this.handler.getMessage());
        }
        return true;
    }

    /**
     * dubbo校验
     * 1.curl http://{{ ansible_eth0.ipv4.address }}:8081/{{ platform }}/
     * 参数:  终端ip    端口  应用名
     * 2.curl -o /home/deploy/dubbo.html -u root:root http://10.32.0.130:8088/dubbo-admin/governance/addresses
     * 参数:  应用对应dubbo地址列表
     *      dubbo登录用户名/密码
     * 3.grep  {{ ansible_eth0.ipv4.address }}   /home/deploy/dubbo.html
     * @throws Exception
     */
    public void doVerify() throws Exception{
        if(this.dubboList == null || this.dubboList.size() == 0){
            logger.error("WinitTomcatServer:校验dubbo,dubbo列表为空.");
//            throw new Exception("校验dubbo,dubbo列表为空");
            return;
        }

        if(StringUtils.isEmpty(this.winitTomcatInfo.getServerIp())
                || StringUtils.isEmpty(this.winitTomcatInfo.getWarName())
                || StringUtils.isEmpty(this.winitTomcatInfo.getHttpPort())){
            logger.error("WinitTomcatServer:校验dubbo,参数存在空值."+ ObjectToString.getString(this.winitTomcatInfo));
            throw new Exception("校验dubbo,参数存在空值");
        }
        this.initHandler();
        this.doExec(this.handler,"curl http://"+this.winitTomcatInfo.getServerIp()+":"
                +this.winitTomcatInfo.getHttpPort()+"/"+this.winitTomcatInfo.getWarName()+"/");
        if(!this.handler.isSuccess()){
            logger.error("WinitTomcatServer:校验dubbo,请求终端服务失败.返回:"+this.handler.getMessage());
            throw new Exception("校验dubbo,请求终端服务失败.返回:"+this.handler.getMessage());
        }

        for (DubboVerifyInfo vo:this.dubboList){
            this.initHandler();
            this.doExec(this.handler,"curl -o /home/deploy/dubbo.html -u "+vo.getUserName()+":"+vo.getUserPass()
                    +" http://"+vo.getDubboIp()+":"+vo.getDubboPort()+"/dubbo-admin/governance/addresses");
            if(!this.handler.isSuccess()){
                logger.error("WinitTomcatServer:校验dubbo,请求dubbo服务失败.返回:"+this.handler.getMessage());
                throw new Exception("校验dubbo,请求dubbo服务失败.返回:"+this.handler.getMessage());
            }
            this.initHandler();
            this.doExec(this.handler,"grep "+this.winitTomcatInfo.getServerIp()+" /home/deploy/dubbo.html");
            if(!this.handler.isSuccess() || StringUtils.isEmpty(this.handler.getMessage())){
                logger.error("WinitTomcatServer:校验dubbo,查询终端是否注册成功失败.返回:"+this.handler.getMessage());
                throw new Exception("校验dubbo,查询终端是否注册成功失败.返回:"+this.handler.getMessage());
            }
        }
    }

    /**
     * 回滚
     * 1.删除tomcat缓存及工程目录
     * 2.将备份的文件解压到tomcat的webapps目录下
     * @throws Exception
     */
    public void doRollBack() throws Exception{
        if(StringUtils.isEmpty(this.winitTomcatInfo.getProjectDir())
                || StringUtils.isEmpty(this.winitTomcatInfo.getWarName())
                || StringUtils.isEmpty(this.winitTomcatInfo.getBackUpPath())){
            logger.error("WinitTomcatServer:执行回滚,参数存在空值."+ ObjectToString.getString(this.winitTomcatInfo));
            throw new Exception("执行回滚,参数存在空值");
        }
        //1.判断回滚包是否存在
        this.initHandler();
        this.doExec(this.handler,"ls "+this.winitTomcatInfo.getBackUpPath());
        if( StringUtils.isEmpty(this.handler.getMessage())
                || this.handler.getMessage().indexOf("No such file or directory") != -1){
            throw new Exception("执行回滚,备份包不存在."+this.winitTomcatInfo.getBackUpPath());
        }

        StringBuffer cmd = new StringBuffer();
        cmd.append("rm -rf ").append(this.winitTomcatInfo.getProjectDir()).append("/").append(this.winitTomcatInfo.getWarName())
                .append(" && tar -zxf ").append(this.winitTomcatInfo.getBackUpPath()).append(" -C ")
                .append(this.winitTomcatInfo.getProjectDir()).append("/");
        this.initHandler();
        this.doExec(this.handler,cmd.toString());

        if(!this.handler.isSuccess()){
            logger.error("WinitTomcatServer:代码回滚失败.返回:"+this.handler.getMessage());
            throw new Exception("代码回滚失败.返回:"+this.handler.getMessage());
        }
    }

    /**
     * 停止tomcat
     * 1.进入tomcat目录
     * 2.执行tomcat.sh stop
     * 根据返回判断成功状态
     */
    @Override
    public void doStopServer(CmdOutputHandler handler) throws Exception{
        this.doExec(handler,this.getOperateServerCmd("stop"));
    }

    @Override
    public void doStopServer() throws Exception{
        this.doExec(this.getOperateServerCmd("stop"));
    }

    private String getOperateServerCmd(String type) throws Exception{
        String serverPath = this.winitTomcatInfo.getServerPath();
        String system = this.winitTomcatInfo.getSystem();
        String javaHome = this.winitTomcatInfo.getJavaHome();
        String port = this.winitTomcatInfo.getHttpPort();
        if(StringUtils.isEmpty(serverPath)
                || StringUtils.isEmpty(system)
                || StringUtils.isEmpty(javaHome)
                || StringUtils.isEmpty(port)){
            logger.error("com.winit.deploy.server.WinitTomcatServer.getOperateServerCmd,参数存在空值."+ ObjectToString.getString(this.winitTomcatInfo));
            throw new Exception(type+",参数存在空值");
        }
        StringBuffer cmd = new StringBuffer();
        cmd.append("source /etc/profile;cd ").append(serverPath).append(";bash tomcat.sh ").append(type).append(" ")
                .append(system).append(" ").append(javaHome).append(" ")
                .append(serverPath).append(" ").append(port);
        return cmd.toString();
    }

    /**
     * 查询服务器状态
     * @throws Exception
     */
    public void serverStatus(CmdOutputHandler handler) throws Exception{
        this.doExec(handler,this.getOperateServerCmd("status"));
    }

    public void killServer(CmdOutputHandler handler) throws Exception{
        this.doExec(handler,this.getOperateServerCmd("kill"));
    }

    /**
     * 启动tomcat
     * 1.进入tomcat目录
     * 2.执行tomcat.sh start
     * 根据返回判断成功状态
     */
    @Override
    public void doStartServer(CmdOutputHandler handler) throws Exception{
        this.updateConfigFile();
        this.doExec(handler,this.getOperateServerCmd("start"));
    }
    @Override
    public void doStartServer() throws Exception{
        this.updateConfigFile();
        this.doExec(this.getOperateServerCmd("start"));
    }

    /**
     * vm环境发布时,启动前需要刷新下配置
     */
    private void updateConfigFile() {
        if(!this.winitTomcatInfo.isVmEnv()){
            return;
        }

        StringBuffer cmd = new StringBuffer();
        cmd.append("source /etc/profile;ccvm ").append(ProjectUtil.getTrunkProjectName(this.winitTomcatInfo.getProjectName()))
                .append(" ").append(this.winitTomcatInfo.getConfigPath().split("/")[1]);
        try {
            this.doExec(cmd.toString());
        } catch (Exception e) {
            logger.error("虚拟机发布,启动tomcat前刷新配置异常",e);
        }
    }

    public void checkTomcatPermisson() throws Exception{
        final StringBuffer str = new StringBuffer();
        CmdOutputHandler handler = new CmdOutputHandler(){
            @Override
            public void onMessage(String cmd, int index, String message, Boolean isErrorMessage) {
                str.append(message);
            }
        };
        this.doExec(handler,this.getOperateServerCmd("check"));
        logger.info("WinitTomcatServer:校验tomcat权限,返回:"+str.toString());
        if(str.toString().contains("Some dirs or files permisson are uncorrect!please modify it")
                || str.toString().contains("tomcat daemon  user is not beetle")){
            throw new Exception("tomcat权限异常,"+str.toString());
        }
    }
}
